Skip to contentMethod: registerInstance(URI, Object, URI)
1: /**
2: * Copyright (C) 2016 Czech Technical University in Prague
3: *
4: * This program is free software: you can redistribute it and/or modify it under
5: * the terms of the GNU General Public License as published by the Free Software
6: * Foundation, either version 3 of the License, or (at your option) any
7: * later version.
8: *
9: * This program is distributed in the hope that it will be useful, but WITHOUT
10: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12: * details. You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: */
15: package cz.cvut.kbss.jopa.oom;
16:
17: import cz.cvut.kbss.jopa.exceptions.StorageAccessException;
18: import cz.cvut.kbss.jopa.model.descriptors.Descriptor;
19: import cz.cvut.kbss.jopa.model.descriptors.EntityDescriptor;
20: import cz.cvut.kbss.jopa.model.metamodel.EntityType;
21: import cz.cvut.kbss.jopa.model.metamodel.Metamodel;
22: import cz.cvut.kbss.jopa.oom.exceptions.EntityDeconstructionException;
23: import cz.cvut.kbss.jopa.oom.exceptions.EntityReconstructionException;
24: import cz.cvut.kbss.jopa.oom.exceptions.UnpersistedChangeException;
25: import cz.cvut.kbss.jopa.sessions.LoadingParameters;
26: import cz.cvut.kbss.jopa.sessions.UnitOfWorkImpl;
27: import cz.cvut.kbss.jopa.utils.Configuration;
28: import cz.cvut.kbss.jopa.utils.EntityPropertiesUtils;
29: import cz.cvut.kbss.ontodriver.Connection;
30: import cz.cvut.kbss.ontodriver.descriptor.AxiomDescriptor;
31: import cz.cvut.kbss.ontodriver.descriptor.ReferencedListDescriptor;
32: import cz.cvut.kbss.ontodriver.descriptor.SimpleListDescriptor;
33: import cz.cvut.kbss.ontodriver.exception.OntoDriverException;
34: import cz.cvut.kbss.ontodriver.model.*;
35: import org.slf4j.Logger;
36: import org.slf4j.LoggerFactory;
37:
38: import java.lang.reflect.Field;
39: import java.net.URI;
40: import java.util.Collection;
41: import java.util.Map;
42: import java.util.Map.Entry;
43: import java.util.Objects;
44:
45: public class ObjectOntologyMapperImpl implements ObjectOntologyMapper, EntityMappingHelper {
46:
47: private static final Logger LOG = LoggerFactory.getLogger(ObjectOntologyMapperImpl.class);
48:
49: private final UnitOfWorkImpl uow;
50: private final Connection storageConnection;
51: private final Metamodel metamodel;
52:
53: private final AxiomDescriptorFactory descriptorFactory;
54: private final EntityConstructor entityBuilder;
55: private final EntityDeconstructor entityBreaker;
56: private final InstanceRegistry instanceRegistry;
57: private final PendingChangeRegistry pendingPersists;
58:
59: public ObjectOntologyMapperImpl(UnitOfWorkImpl uow, Connection connection) {
60: this.uow = Objects.requireNonNull(uow);
61: this.storageConnection = Objects.requireNonNull(connection);
62: this.metamodel = uow.getMetamodel();
63: this.descriptorFactory = new AxiomDescriptorFactory();
64: this.instanceRegistry = new InstanceRegistry();
65: this.pendingPersists = new PendingChangeRegistry();
66: this.entityBuilder = new EntityConstructor(this);
67: this.entityBreaker = new EntityDeconstructor(this);
68: }
69:
70: @Override
71: public <T> boolean containsEntity(Class<T> cls, URI primaryKey, Descriptor descriptor) {
72: assert cls != null;
73: assert primaryKey != null;
74:
75: final EntityType<T> et = getEntityType(cls);
76: final URI classUri = et.getIRI().toURI();
77: final Axiom<URI> ax = new AxiomImpl<>(NamedResource.create(primaryKey),
78: Assertion.createClassAssertion(false), new Value<>(classUri));
79: try {
80: return storageConnection.contains(ax, descriptor.getContext());
81: } catch (OntoDriverException e) {
82: throw new StorageAccessException(e);
83: }
84: }
85:
86: @Override
87: public <T> T loadEntity(LoadingParameters<T> loadingParameters) {
88: assert loadingParameters != null;
89:
90: instanceRegistry.reset();
91: return loadEntityInternal(loadingParameters);
92: }
93:
94: private <T> T loadEntityInternal(LoadingParameters<T> loadingParameters) {
95: final EntityType<T> et = getEntityType(loadingParameters.getEntityType());
96: final AxiomDescriptor axiomDescriptor = descriptorFactory.createForEntityLoading(loadingParameters, et);
97: try {
98: final Collection<Axiom<?>> axioms = storageConnection.find(axiomDescriptor);
99: if (axioms.isEmpty()) {
100: return null;
101: }
102: return entityBuilder
103: .reconstructEntity(loadingParameters.getIdentifier(), et, loadingParameters.getDescriptor(),
104: axioms);
105: } catch (OntoDriverException e) {
106: throw new StorageAccessException(e);
107: } catch (InstantiationException | IllegalAccessException e) {
108: throw new EntityReconstructionException(e);
109: }
110: }
111:
112: @Override
113: public <T> EntityType<T> getEntityType(Class<T> cls) {
114: return metamodel.entity(cls);
115: }
116:
117: @Override
118: public <T> void loadFieldValue(T entity, Field field, Descriptor descriptor) {
119: assert entity != null;
120: assert field != null;
121: assert descriptor != null;
122:
123: LOG.trace("Lazily loading value of field {} of entity ", field, entity);
124:
125: final EntityType<T> et = (EntityType<T>) getEntityType(entity.getClass());
126: final URI primaryKey = EntityPropertiesUtils.getPrimaryKey(entity, et);
127:
128: final AxiomDescriptor axiomDescriptor = descriptorFactory.createForFieldLoading(primaryKey,
129: field, descriptor, et);
130: try {
131: final Collection<Axiom<?>> axioms = storageConnection.find(axiomDescriptor);
132: if (axioms.isEmpty()) {
133: return;
134: }
135: entityBuilder.setFieldValue(entity, field, axioms, et, descriptor);
136: } catch (OntoDriverException e) {
137: throw new StorageAccessException(e);
138: } catch (IllegalArgumentException | IllegalAccessException e) {
139: throw new EntityReconstructionException(e);
140: }
141: }
142:
143: @Override
144: public <T> void persistEntity(URI primaryKey, T entity, Descriptor descriptor) {
145: assert entity != null;
146: assert descriptor != null;
147:
148: @SuppressWarnings("unchecked")
149: final EntityType<T> et = (EntityType<T>) getEntityType(entity.getClass());
150: try {
151: if (primaryKey == null) {
152: primaryKey = generateIdentifier(et);
153: assert primaryKey != null;
154: EntityPropertiesUtils.setPrimaryKey(primaryKey, entity, et);
155: }
156: entityBreaker.setCascadeResolver(new PersistCascadeResolver(this));
157: final AxiomValueGatherer axiomBuilder = entityBreaker.mapEntityToAxioms(primaryKey,
158: entity, et, descriptor);
159: axiomBuilder.persist(storageConnection);
160: pendingPersists.removeInstance(primaryKey, descriptor.getContext());
161: } catch (IllegalArgumentException e) {
162: throw new EntityDeconstructionException("Unable to deconstruct entity " + entity, e);
163: }
164: }
165:
166: @Override
167: public URI generateIdentifier(EntityType<?> et) {
168: try {
169: return storageConnection.generateIdentifier(et.getIRI().toURI());
170: } catch (OntoDriverException e) {
171: throw new StorageAccessException(e);
172: }
173: }
174:
175: @Override
176: public <T> T getEntityFromCacheOrOntology(Class<T> cls, URI primaryKey, Descriptor descriptor) {
177: final T orig = uow.getManagedOriginal(cls, primaryKey, descriptor);
178: if (orig != null) {
179: return orig;
180: }
181: if (uow.getLiveObjectCache().contains(cls, primaryKey, descriptor.getContext())) {
182: return uow.getLiveObjectCache().get(cls, primaryKey, descriptor.getContext());
183: } else if (instanceRegistry.containsInstance(primaryKey, descriptor.getContext())) {
184: // This prevents endless cycles in bidirectional relationships
185: return cls.cast(instanceRegistry.getInstance(primaryKey, descriptor.getContext()));
186: } else {
187: return loadEntityInternal(new LoadingParameters<>(cls, primaryKey, descriptor));
188: }
189: }
190:
191: @Override
192: public <T> T getOriginalInstance(T clone) {
193: assert clone != null;
194: return (T) uow.getOriginal(clone);
195: }
196:
197: <T> void registerInstance(URI primaryKey, T instance, URI context) {
198: instanceRegistry.registerInstance(primaryKey, instance, context);
199: }
200:
201: @Override
202: public void checkForUnpersistedChanges() {
203: try {
204: final Map<URI, Map<URI, Object>> persists = pendingPersists.getInstances();
205: if (!persists.isEmpty()) {
206: for (URI ctx : persists.keySet()) {
207: for (Entry<URI, Object> e : persists.get(ctx).entrySet()) {
208: verifyInstanceExistInOntology(ctx, e.getKey(), e.getValue());
209: }
210: }
211: }
212: } catch (OntoDriverException e) {
213: throw new StorageAccessException(e);
214: }
215: }
216:
217: private void verifyInstanceExistInOntology(URI ctx, URI primaryKey, Object instance)
218: throws OntoDriverException {
219: boolean exists = containsEntity(instance.getClass(), primaryKey, new EntityDescriptor(ctx));
220: if (!exists) {
221: throw new UnpersistedChangeException(
222: "Encountered an instance that was neither persisted nor marked as cascade for persist. The instance: "
223: + instance);
224: }
225: }
226:
227: <T> void registerPendingPersist(URI primaryKey, T entity, URI context) {
228: pendingPersists.registerInstance(primaryKey, entity, context);
229: }
230:
231: @Override
232: public <T> void removeEntity(URI primaryKey, Class<T> cls, Descriptor descriptor) {
233: final EntityType<T> et = getEntityType(cls);
234: final AxiomDescriptor axiomDescriptor = descriptorFactory.createForEntityLoading(
235: new LoadingParameters<>(cls, primaryKey, descriptor, true), et);
236: try {
237: storageConnection.remove(axiomDescriptor);
238: } catch (OntoDriverException e) {
239: throw new StorageAccessException("Exception caught when removing entity.", e);
240: }
241: }
242:
243: @Override
244: public <T> void updateFieldValue(T entity, Field field, Descriptor descriptor) {
245: @SuppressWarnings("unchecked")
246: final EntityType<T> et = (EntityType<T>) getEntityType(entity.getClass());
247: final URI pkUri = EntityPropertiesUtils.getPrimaryKey(entity, et);
248:
249: entityBreaker.setCascadeResolver(new PersistCascadeResolver(this));
250: final AxiomValueGatherer axiomBuilder = entityBreaker.mapFieldToAxioms(pkUri, entity, field,
251: et, descriptor);
252: axiomBuilder.update(storageConnection);
253: }
254:
255: @Override
256: public Collection<Axiom<NamedResource>> loadSimpleList(SimpleListDescriptor listDescriptor) {
257: try {
258: return storageConnection.lists().loadSimpleList(listDescriptor);
259: } catch (OntoDriverException e) {
260: throw new StorageAccessException(e);
261: }
262: }
263:
264: @Override
265: public Collection<Axiom<NamedResource>> loadReferencedList(ReferencedListDescriptor listDescriptor) {
266: try {
267: return storageConnection.lists().loadReferencedList(listDescriptor);
268: } catch (OntoDriverException e) {
269: throw new StorageAccessException(e);
270: }
271: }
272:
273: @Override
274: public Configuration getConfiguration() {
275: return uow.getConfiguration();
276: }
277: }